package io.gitee.zhangbinhub.admin.workflow.service

import com.mybatisflex.core.query.QueryChain
import com.mybatisflex.core.table.TableInfoFactory
import io.gitee.zhangbinhub.acp.boot.exceptions.WebException
import io.gitee.zhangbinhub.acp.boot.log.LogAdapter
import io.gitee.zhangbinhub.acp.core.common.CommonTools
import io.gitee.zhangbinhub.admin.common.vo.CustomerQueryPageVo
import io.gitee.zhangbinhub.admin.resource.server.feign.CommonOauthServer
import io.gitee.zhangbinhub.admin.resource.server.po.*
import io.gitee.zhangbinhub.admin.resource.server.vo.ProcessHisTaskVo
import io.gitee.zhangbinhub.admin.resource.server.vo.ProcessInstanceVo
import io.gitee.zhangbinhub.admin.resource.server.vo.ProcessTaskVo
import io.gitee.zhangbinhub.admin.resource.server.vo.UserVo
import io.gitee.zhangbinhub.admin.workflow.base.BaseWorkFlowService
import io.gitee.zhangbinhub.admin.workflow.component.WorkFlowGlobalListener
import io.gitee.zhangbinhub.admin.workflow.component.WorkFlowPermissionHandler
import io.gitee.zhangbinhub.admin.workflow.constant.WorkFlowParamKey
import io.gitee.zhangbinhub.admin.workflow.repo.MyProcessInstanceRepository
import jakarta.persistence.criteria.Predicate
import org.dromara.warm.flow.core.FlowEngine
import org.dromara.warm.flow.core.dto.DefJson
import org.dromara.warm.flow.core.dto.FlowParams
import org.dromara.warm.flow.core.entity.HisTask
import org.dromara.warm.flow.core.entity.Instance
import org.dromara.warm.flow.core.entity.Task
import org.dromara.warm.flow.core.enums.CooperateType
import org.dromara.warm.flow.core.enums.NodeType
import org.dromara.warm.flow.core.enums.SkipType
import org.dromara.warm.flow.core.enums.UserType
import org.dromara.warm.flow.core.service.*
import org.dromara.warm.flow.core.utils.page.Page
import org.dromara.warm.flow.orm.entity.FlowDefinition
import org.dromara.warm.flow.orm.entity.FlowTask
import org.dromara.warm.flow.orm.entity.FlowUser
import org.dromara.warm.flow.orm.mapper.FlowTaskMapper
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
@Transactional(transactionManager = "mybatisFlexTransactionManager", readOnly = true)
class WorkFlowService(
    private val logAdapter: LogAdapter,
    private val myProcessInstanceRepository: MyProcessInstanceRepository,
    private val commonOauthServer: CommonOauthServer,
    private val defService: DefService,
    private val insService: InsService,
    private val taskService: TaskService,
    private val userService: UserService,
    private val hisTaskService: HisTaskService,
    private val flowTaskMapper: FlowTaskMapper,
    private val workFlowPermissionHandler: WorkFlowPermissionHandler,
    private val workFlowGlobalListener: WorkFlowGlobalListener,
    private val myProcessInstanceService: MyProcessInstanceService
) : BaseWorkFlowService() {
    @Throws(WebException::class)
    private fun getUserById(id: String?): UserVo = if (CommonTools.isNullStr(id)) {
        UserVo()
    } else {
        commonOauthServer.findUserById(id!!).also {
            if (it.loginNo == null) {
                throw WebException("获取当前登录用户信息失败！")
            }
        }
    }

    /**
     * 获取待办人员
     */
    private fun getPendingUser(task: Task): List<UserVo> = task.userList.flatMap { flowUser ->
        workFlowPermissionHandler.userIdList(listOf(flowUser.processedBy)).map { userId ->
            getUserById(userId).apply {
                this.remark = UserType.getValueByKey(flowUser.type)
            }
        }
    }

    /**
     * 任务实体转换
     *
     * @param flowTask 任务对象
     * @return 转换后任务对象
     */
    @Throws(WebException::class)
    private fun taskToVo(flowTask: Task): ProcessTaskVo = insService.getById(flowTask.instanceId).let { flowInstance ->
        val params = flowInstance.variableMap
        val defJson = FlowEngine.jsonConvert.strToBean(flowInstance.defJson, DefJson::class.java)
        if (flowTask.userList == null) {
            flowTask.userList = userService.list(FlowEngine.newUser().setAssociated(flowTask.id))
        }
        return ProcessTaskVo(
            processInstanceId = flowTask.instanceId.toString(),
            processDefinitionKey = defService.getById(flowTask.definitionId).flowCode,
            flowName = defJson.flowName,
            taskId = flowTask.id.toString(),
            nodeCode = flowTask.nodeCode,
            nodeName = flowTask.nodeName,
            businessKey = flowTask.businessId,
            params = params,
            createTime = flowTask.createTime.time,
            title = params[WorkFlowParamKey.title]?.toString() ?: "",
            description = params[WorkFlowParamKey.description]?.toString() ?: "",
            startUser = getUserById(flowInstance.createBy),
            pendingUserList = getPendingUser(flowTask)
        )
    }

    /**
     * 历史记录实例转换
     *
     * @param flowHisTask 历史记录
     * @return 转换后对象
     */
    private fun hisTaskToVo(flowHisTask: HisTask): ProcessHisTaskVo =
        insService.getById(flowHisTask.instanceId).let { flowInstance ->
            val params = flowInstance.variableMap
            val defJson = FlowEngine.jsonConvert.strToBean(flowInstance.defJson, DefJson::class.java)
            return ProcessHisTaskVo(
                processInstanceId = flowHisTask.instanceId.toString(),
                processDefinitionKey = defService.getById(flowHisTask.definitionId).flowCode,
                flowName = defJson.flowName,
                taskId = flowHisTask.id.toString(),
                nodeCode = flowHisTask.nodeCode,
                nodeName = flowHisTask.nodeName,
                businessKey = flowHisTask.businessId,
                params = params,
                createTime = flowHisTask.createTime.time,
                updateTime = flowHisTask.updateTime.time,
                user = getUserById(flowHisTask.approver),
                message = flowHisTask.message,
                skipType = flowHisTask.skipType
            )
        }

    /**
     * 流程实例转换
     * @param flowInstance 流程实例
     * @return 转换后的对象
     */
    @Throws(WebException::class)
    private fun instanceToVo(flowInstance: Instance): ProcessInstanceVo {
        val params = flowInstance.variableMap
        val defJson = FlowEngine.jsonConvert.strToBean(flowInstance.defJson, DefJson::class.java)
        return ProcessInstanceVo(
            processInstanceId = flowInstance.id.toString(),
            processDefinitionKey = defService.getById(flowInstance.definitionId).flowCode,
            businessKey = flowInstance.businessId,
            flowName = defJson.flowName,
            title = params[WorkFlowParamKey.title]?.toString() ?: "",
            description = params[WorkFlowParamKey.description]?.toString() ?: "",
            startUser = getUserById(flowInstance.createBy),
            activityUser = taskService.list(FlowEngine.newTask().apply {
                this.instanceId = flowInstance.id
            }).flatMap { flowTask ->
                getPendingUser(flowTask.apply {
                    flowTask.userList = userService.list(FlowEngine.newUser().setAssociated(flowTask.id))
                })
            }.toMutableList(),
            params = params,
            nodeCode = flowInstance.nodeCode,
            nodeName = flowInstance.nodeName,
            startTime = flowInstance.createTime!!.time,
            updateTime = flowInstance.updateTime!!.time,
            activityStatus = flowInstance.activityStatus,
            status = flowInstance.flowStatus,
            finished = NodeType.isEnd(flowInstance.nodeType)
        )
    }

    @Throws(WebException::class)
    private fun getTask(taskId: Long): Task = taskService.getById(taskId)?.apply {
        this.userList = userService.list(FlowEngine.newUser().setAssociated(taskId))
    } ?: run {
        logAdapter.error("流程任务【$taskId】不存在！")
        throw WebException("流程任务不存在！")
    }

    /**
     * 启动流程
     *
     * @param processStartPo 流程启动参数
     * @param userId 流程发起人ID
     * @return 流程实例id
     */
    @Transactional
    @Throws(WebException::class)
    fun startFlow(processStartPo: ProcessStartPo, userId: String? = null): Instance = try {
        val flowParams = FlowParams().variable(processStartPo.params).flowCode(processStartPo.processDefinitionKey)
        flowParams.variable[WorkFlowParamKey.title] = processStartPo.title!!
        flowParams.variable[WorkFlowParamKey.description] = processStartPo.description!!
        userId?.apply {
            flowParams.variable[WorkFlowParamKey.startUserId] = this
            flowParams.handler(this)
        }
        insService.start(processStartPo.businessKey, flowParams).also {
            logAdapter.info(
                "流程启动成功：流程定义【${processStartPo.processDefinitionKey}】流程实例ID【${it.id}】业务KEY【${it.businessId}】启动人【${
                    getUserById(
                        userId
                    ).loginNo
                }】"
            )
        }
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }

    @Transactional
    @Throws(WebException::class)
    fun terminationFlow(processTerminationPo: ProcessTerminationPo, userId: String? = null): Instance = try {
        val flowParams = FlowParams().message(processTerminationPo.reason).ignore(true)
        userId?.apply {
            flowParams.handler(this)
        }
        taskService.terminationByInsId(processTerminationPo.processInstanceId, flowParams).also { instance ->
            logAdapter.info(
                "任务终止成功：流程实例ID【${instance.id}】操作人【${
                    getUserById(
                        userId
                    ).loginNo
                }】"
            )
        }
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }

    @Transactional
    @Throws(WebException::class)
    fun terminationTask(
        processTerminationPo: ProcessTerminationPo, taskId: Long, userId: String? = null
    ): Instance = try {
        val flowParams = FlowParams().message(processTerminationPo.reason).ignore(true)
        userId?.apply {
            flowParams.handler(this)
        }
        taskService.termination(taskId, flowParams).also { instance ->
            logAdapter.info(
                "任务终止成功：流程实例ID【${instance.id}】操作人【${
                    getUserById(
                        userId
                    ).loginNo
                }】"
            )
        }
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }

    /**
     * 转办
     *
     * @param taskId 任务id
     */
    @Transactional
    @Throws(WebException::class)
    fun transferAdmin(loginNo: String, taskId: Long, acceptUserId: String) {
        try {
            commonOauthServer.findUserByLoginNo(loginNo).let { userInfo ->
                if (userInfo.id == null) {
                    throw WebException("获取当前登录用户信息失败！")
                }
                val task = getTask(taskId)
                if (taskService.updateHandler(
                        taskId,
                        FlowParams().handler(userInfo.id)
                            .addHandlers(listOf(acceptUserId))
                            .reductionHandlers(task.userList.map { it.processedBy })
                            .cooperateType(CooperateType.TRANSFER.key)
                            .message("任务转办").ignore(true)
                    )
                ) {
                    workFlowGlobalListener.notifyPendingFinished(
                        insService.getById(task.instanceId),
                        task,
                        getPendingUser(task).mapNotNull { it.id }
                    )
                    logAdapter.info(
                        "任务转办成功：流程实例ID【${task.instanceId}】任务ID【$taskId】操作人【${userInfo.loginNo}】新办理人【${
                            getUserById(
                                acceptUserId
                            ).loginNo
                        }】"
                    )
                } else {
                    logAdapter.info(
                        "任务转办失败：流程实例ID【${task.instanceId}】任务ID【$taskId】操作人【${userInfo.loginNo}】"
                    )
                }
            }
        } catch (e: Exception) {
            logAdapter.error(e.message, e)
            throw WebException(e.message)
        }
    }

    /**
     * 转办
     *
     * @param taskId 任务id
     */
    @Transactional
    @Throws(WebException::class)
    fun transfer(loginNo: String, taskId: Long, acceptUserId: String) {
        try {
            commonOauthServer.findUserByLoginNo(loginNo).let { userInfo ->
                if (userInfo.id == null) {
                    throw WebException("获取当前登录用户信息失败！")
                }
                val task = getTask(taskId)
                if (taskService.transfer(
                        taskId, FlowParams().handler(userInfo.id)
                            .permissionFlag(
                                workFlowPermissionHandler.permissions(listOf(userInfo.id!!)).toMutableList()
                            )
                            .addHandlers(listOf(acceptUserId)).message("任务转办")
                    )
                ) {
                    workFlowGlobalListener.notifyPendingFinished(
                        insService.getById(task.instanceId), task, listOf(userInfo.id!!)
                    )
                    logAdapter.info(
                        "任务转办成功：流程实例ID【${task.instanceId}】任务ID【$taskId】操作人【${userInfo.loginNo}】新办理人【${
                            getUserById(
                                acceptUserId
                            ).loginNo
                        }】"
                    )
                } else {
                    logAdapter.info(
                        "任务转办失败：流程实例ID【${task.instanceId}】任务ID【$taskId】操作人【${userInfo.loginNo}】"
                    )
                }
            }
        } catch (e: Exception) {
            logAdapter.error(e.message, e)
            throw WebException(e.message)
        }
    }

    /**
     * 委派
     *
     * @param taskId 任务id
     */
    @Transactional
    @Throws(WebException::class)
    fun depute(loginNo: String, taskId: Long, acceptUserId: String) {
        try {
            commonOauthServer.findUserByLoginNo(loginNo).let { userInfo ->
                if (userInfo.id == null) {
                    throw WebException("获取当前登录用户信息失败！")
                }
                val task = getTask(taskId)
                if (taskService.depute(
                        taskId,
                        FlowParams().handler(userInfo.id)
                            .permissionFlag(
                                workFlowPermissionHandler.permissions(listOf(userInfo.id!!)).toMutableList()
                            )
                            .addHandlers(listOf(acceptUserId)).message("任务委派")
                    )
                ) {
                    workFlowGlobalListener.notifyPendingFinished(
                        insService.getById(task.instanceId), task, listOf(userInfo.id!!)
                    )
                    logAdapter.info(
                        "任务委派成功：流程实例ID【${task.instanceId}】任务ID【$taskId】操作人【${userInfo.loginNo}】新办理人【${
                            getUserById(
                                acceptUserId
                            ).loginNo
                        }】"
                    )
                } else {
                    logAdapter.info(
                        "任务委派失败：流程实例ID【${task.instanceId}】任务ID【$taskId】操作人【${userInfo.loginNo}】"
                    )
                }
            }
        } catch (e: Exception) {
            logAdapter.error(e.message, e)
            throw WebException(e.message)
        }
    }

    /**
     * 加签
     *
     * @param taskId 任务id
     */
    @Transactional
    @Throws(WebException::class)
    fun addSignature(loginNo: String, taskId: Long, acceptUserId: String) {
        try {
            commonOauthServer.findUserByLoginNo(loginNo).let { userInfo ->
                if (userInfo.id == null) {
                    throw WebException("获取当前登录用户信息失败！")
                }
                val task = getTask(taskId)
                if (taskService.addSignature(
                        taskId,
                        FlowParams().handler(userInfo.id)
                            .permissionFlag(
                                workFlowPermissionHandler.permissions(listOf(userInfo.id!!)).toMutableList()
                            )
                            .addHandlers(listOf(acceptUserId)).message("任务加签")
                    )
                ) {
                    logAdapter.info(
                        "任务加签成功：流程实例ID【${task.instanceId}】任务ID【$taskId】操作人【${userInfo.loginNo}】新增办理人【${
                            getUserById(
                                acceptUserId
                            ).loginNo
                        }】"
                    )
                } else {
                    logAdapter.info(
                        "任务加签失败：流程实例ID【${task.instanceId}】任务ID【$taskId】操作人【${userInfo.loginNo}】"
                    )
                }
            }
        } catch (e: Exception) {
            logAdapter.error(e.message, e)
            throw WebException(e.message)
        }
    }

    /**
     * 减签
     *
     * @param taskId 任务id
     */
    @Transactional
    @Throws(WebException::class)
    fun reductionSignature(loginNo: String, taskId: Long, acceptUserId: String) {
        try {
            commonOauthServer.findUserByLoginNo(loginNo).let { userInfo ->
                if (userInfo.id == null) {
                    throw WebException("获取当前登录用户信息失败！")
                }
                val task = getTask(taskId)
                if (taskService.reductionSignature(
                        taskId,
                        FlowParams().handler(userInfo.id)
                            .permissionFlag(
                                workFlowPermissionHandler.permissions(listOf(userInfo.id!!)).toMutableList()
                            )
                            .reductionHandlers(listOf(acceptUserId)).message("任务减签")
                    )
                ) {
                    workFlowGlobalListener.notifyPendingFinished(
                        insService.getById(task.instanceId), task, listOf(acceptUserId)
                    )
                    logAdapter.info(
                        "任务减签成功：流程实例ID【${task.instanceId}】任务ID【$taskId】操作人【${userInfo.loginNo}】删除办理人【${
                            getUserById(
                                acceptUserId
                            ).loginNo
                        }】"
                    )
                } else {
                    logAdapter.info(
                        "任务减签失败：流程实例ID【${task.instanceId}】任务ID【$taskId】操作人【${userInfo.loginNo}】"
                    )
                }
            }
        } catch (e: Exception) {
            logAdapter.error(e.message, e)
            throw WebException(e.message)
        }
    }

    /**
     * 任务处理
     *
     * @param processHandlingPo 任务处理参数
     */
    @Transactional
    @Throws(WebException::class)
    fun skip(processHandlingPo: ProcessHandlingPo, userId: String): Instance = try {
        commonOauthServer.findUserById(userId).let { userInfo ->
            if (userInfo.loginNo == null) {
                throw WebException("获取当前登录用户信息失败！")
            }
            val comment = if (processHandlingPo.pass!!) {
                if (CommonTools.isNullStr(processHandlingPo.message)) {
                    "通过"
                } else {
                    processHandlingPo.message!!
                }
            } else {
                if (CommonTools.isNullStr(processHandlingPo.message)) {
                    "不通过"
                } else {
                    processHandlingPo.message!!
                }
            }
            val task = getTask(processHandlingPo.taskId!!)
            taskService.skip(
                FlowParams().handler(userInfo.id)
                    .permissionFlag(workFlowPermissionHandler.permissions(listOf(userInfo.id!!)).toMutableList())
                    .skipType(if (processHandlingPo.pass!!) SkipType.PASS.key else SkipType.REJECT.key)
                    .variable(processHandlingPo.params).message(comment), task
            ).also { instance ->
                logAdapter.info(
                    "任务处理完成：流程实例ID【${task.instanceId}】任务ID【${processHandlingPo.taskId}】操作人【${
                        getUserById(
                            userId
                        ).loginNo
                    }】意见【$comment】"
                )
                // 添加至我处理过的流程实例
                myProcessInstanceService.addMyProcessInstance(userId, instance, findProcessInstance(instance.id))
            }
        } ?: throw WebException("获取当前登录用户信息失败！")
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }


    @Throws(WebException::class)
    fun findProcessInstance(processInstanceId: Long): ProcessInstanceVo = try {
        insService.getById(processInstanceId)?.let { instanceToVo(it) } ?: throw WebException("流程实例不存在！")
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }

    /**
     * 查询流程实例
     */
    @Throws(WebException::class)
    fun findProcessInstance(processQueryPo: ProcessQueryPo): CustomerQueryPageVo<ProcessInstanceVo> = try {
        insService.orderByCreateTime().desc().page(FlowEngine.newIns().apply {
            if (processQueryPo.processInstanceId != null) {
                this.id = processQueryPo.processInstanceId
            }
            if (!CommonTools.isNullStr(processQueryPo.processBusinessKey)) {
                this.businessId = processQueryPo.processBusinessKey
            }
            if (!CommonTools.isNullStr(processQueryPo.flowStatus)) {
                this.flowStatus = processQueryPo.flowStatus
            }
            if (!CommonTools.isNullStr(processQueryPo.startUserId)) {
                this.createBy = processQueryPo.startUserId
            }
        }, Page<Instance>().apply {
            this.pageNum = processQueryPo.queryParam!!.currPage!!
            this.pageSize = processQueryPo.queryParam!!.pageSize!!
        }).let { result ->
            CustomerQueryPageVo(
                content = result.list.map { instanceToVo(it) },
                totalElements = result.total,
                currPage = result.pageNum,
                pageSize = result.pageSize
            )
        }
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }

    /**
     * 获取任务信息
     *
     * @param taskId 任务ID
     * @return 任务信息
     */
    @Throws(WebException::class)
    fun findTaskById(loginNo: String, taskId: Long): ProcessTaskVo = try {
        commonOauthServer.findUserByLoginNo(loginNo).let { userInfo ->
            if (userInfo.id == null) {
                throw WebException("获取当前登录用户信息失败！")
            }
            getTask(taskId).let { task ->
                if (getPendingUser(task).map { it.id }.contains(userInfo.id)) {
                    taskToVo(task)
                } else {
                    throw WebException("找不到任务信息")
                }
            }
        }
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }

    /**
     * 获取任务信息（开放的）
     *
     * @param taskId 任务ID
     * @return 任务信息
     */
    @Throws(WebException::class)
    fun findTaskByIdOpen(taskId: Long): ProcessTaskVo = try {
        taskToVo(getTask(taskId))
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }

    /**
     * 获取待办任务
     * @param processInstanceId 流程实例ID
     * @param userId 用户ID
     */
    @Throws(WebException::class)
    fun findTaskList(processInstanceId: Long, userId: String? = null): List<ProcessTaskVo> = try {
        val permissions = if (!CommonTools.isNullStr(userId)) {
            workFlowPermissionHandler.permissions(listOf(userId!!))
        } else {
            listOf()
        }
        QueryChain.of(flowTaskMapper).select(*(TableInfoFactory.ofEntityClass(FlowTask::class.java).allColumns))
            .from(FlowTask::class.java).where(FlowTask::getInstanceId).eq(processInstanceId).and(FlowTask::getId).`in`(
                QueryChain.of(FlowUser::class.java).select(FlowUser::getAssociated).from(FlowUser::class.java)
                    .where(FlowUser::getProcessedBy).`in`(permissions), permissions.isNotEmpty()
            ).orderBy(FlowTask::getCreateTime).asc().orderBy(FlowTask::getId).asc().list().map {
                taskToVo(it)
            }
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }

    /**
     * 获取待办任务
     *
     * @return 任务列表
     */
    @Throws(WebException::class)
    fun findTaskList(loginNo: String, processTaskQueryPo: ProcessTaskQueryPo): CustomerQueryPageVo<ProcessTaskVo> =
        try {
            commonOauthServer.findUserByLoginNo(loginNo).let { userInfo ->
                if (userInfo.id == null) {
                    throw WebException("获取当前登录用户信息失败！")
                }
                val permissions = workFlowPermissionHandler.permissions(listOf(userInfo.id!!))
                QueryChain.of(flowTaskMapper)
                    .select(*(TableInfoFactory.ofEntityClass(FlowTask::class.java).allColumns.map { "t.$it" }
                        .toTypedArray())).from(FlowTask::class.java).`as`("t").leftJoin(FlowDefinition::class.java)
                    .`as`("d").on(FlowTask::getDefinitionId, FlowDefinition::getId).where(FlowTask::getInstanceId)
                    .eq(processTaskQueryPo.processInstanceId, processTaskQueryPo.processInstanceId != null)
                    .and(FlowDefinition::getFlowCode).eq(
                        processTaskQueryPo.processBusinessKey,
                        !CommonTools.isNullStr(processTaskQueryPo.processBusinessKey)
                    ).and(FlowTask::getId).`in`(
                        QueryChain.of(FlowUser::class.java).select(FlowUser::getAssociated).from(FlowUser::class.java)
                            .where(FlowUser::getProcessedBy).`in`(permissions), permissions.isNotEmpty()
                    ).orderBy(FlowTask::getCreateTime).asc().orderBy(FlowTask::getId).asc().let { queryChain ->
                        doPageQuery(
                            processTaskQueryPo.queryParam!!.apply { this.orderName = null }, queryChain, true
                        )
                    }.let { result ->
                        CustomerQueryPageVo(
                            content = result.content.map { taskToVo(it) },
                            totalElements = result.totalElements,
                            currPage = result.currPage,
                            pageSize = result.pageSize
                        )
                    }
            }
        } catch (e: Exception) {
            logAdapter.error(e.message, e)
            throw WebException(e.message)
        }

    /**
     * 查询指定流程的历史信息
     *
     * @param processInstanceId 流程id
     * @return 流程历史信息
     */
    @Throws(WebException::class)
    fun findHistoryTask(processInstanceId: Long): List<ProcessHisTaskVo> = try {
        hisTaskService.orderByUpdateTime().list(FlowEngine.newHisTask().apply {
            this.instanceId = processInstanceId
        }).map { hisTaskToVo(it) }
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }

    /**
     * 查询用户已办的流程实例
     */
    @Throws(WebException::class)
    fun findProcessInstanceForMyProcess(
        loginNo: String, myProcessQueryPo: MyProcessQueryPo
    ): CustomerQueryPageVo<ProcessInstanceVo> = try {
        commonOauthServer.findUserByLoginNo(loginNo).let { userInfo ->
            if (userInfo.id == null) {
                throw WebException("获取当前登录用户信息失败！")
            }
            myProcessInstanceRepository.findAll({ root, _, criteriaBuilder ->
                val predicateList: MutableList<Predicate> = mutableListOf()
                predicateList.add(
                    criteriaBuilder.equal(
                        root.get<Any>("userId").`as`(String::class.java), userInfo.id
                    )
                )
                if (myProcessQueryPo.processDefinitionKeys != null && myProcessQueryPo.processDefinitionKeys!!.isNotEmpty()) {
                    predicateList.add(
                        root.get<Any>("processDefinitionKey").`as`(String::class.java)
                            .`in`(myProcessQueryPo.processDefinitionKeys)
                    )
                }
                if (myProcessQueryPo.processInstanceIds != null && myProcessQueryPo.processInstanceIds!!.isNotEmpty()) {
                    predicateList.add(
                        root.get<Any>("processInstanceId").`as`(String::class.java)
                            .`in`(myProcessQueryPo.processInstanceIds)
                    )
                }
                if (!CommonTools.isNullStr(myProcessQueryPo.processBusinessKey)) {
                    predicateList.add(
                        criteriaBuilder.equal(
                            root.get<Any>("businessKey").`as`(String::class.java), myProcessQueryPo.processBusinessKey
                        )
                    )
                }
                if (!CommonTools.isNullStr(myProcessQueryPo.startUserId)) {
                    predicateList.add(
                        criteriaBuilder.equal(
                            root.get<Any>("startUserId").`as`(String::class.java), myProcessQueryPo.startUserId
                        )
                    )
                }
                if (myProcessQueryPo.startTime != null) {
                    predicateList.add(
                        criteriaBuilder.ge(
                            root.get<Any>("startTime").`as`(Long::class.java), myProcessQueryPo.startTime
                        )
                    )
                }
                if (myProcessQueryPo.endTime != null) {
                    predicateList.add(
                        criteriaBuilder.le(
                            root.get<Any>("startTime").`as`(Long::class.java), myProcessQueryPo.endTime
                        )
                    )
                }
                criteriaBuilder.and(*predicateList.toTypedArray())
            }, buildPageRequest(myProcessQueryPo.queryParam!!)).let {
                CustomerQueryPageVo(
                    currPage = myProcessQueryPo.queryParam!!.currPage!!,
                    pageSize = myProcessQueryPo.queryParam!!.pageSize!!,
                    totalElements = it.totalElements,
                    content = it.content.map { instance ->
                        findProcessInstance(instance.processInstanceId)
                    })
            }
        }
    } catch (e: Exception) {
        logAdapter.error(e.message, e)
        throw WebException(e.message)
    }
}
